#pragma once
#include"sock.h"
#include<sys/epoll.h>
#include<string>
namespace ns_epoll
{
    using namespace ns_sock;
    class EpollServer
    {
    private:
        u_int16_t port_;
        int listen_sock_;
        int epfd_;
    public:
        EpollServer(const u_int16_t& port):port_(port),listen_sock_(-1),epfd_(-1)
        {}
        void InitServer()
        {
            listen_sock_=Sock::Socket();
            Sock::Bind(listen_sock_,port_);
            Sock::Listen(listen_sock_);
            //创建epoll模型
            epfd_=epoll_create(1024);
            if(epfd_<0)
            {
                std::cerr<<"epoll create error"<<std::endl;
                exit(-4);
            }
        }
        void Loop()
        {
            //先添加listen_sock到epoll模型中
            struct epoll_event local;
            local.events=EPOLLIN;
            local.data.fd=listen_sock_;
            if(epoll_ctl(epfd_,EPOLL_CTL_ADD,listen_sock_,&local)<0)
            {
                std::cerr<<"epll_ctl add error"<<std::endl;
                exit(-5);
            }
            int timeout=1000; //毫秒
            // 存放就绪容器
#define MAX 128
            struct epoll_event events_[MAX];
            while(true)
            {
                int n=epoll_wait(epfd_,events_,MAX,timeout);
                switch(n)
                {
                    case 0:
                        std::cout<<"time out"<<std::endl;
                        break;
                    case -1:
                        std::cerr<<"epoll_wait error"<<std::endl;
                        break;
                    default:
                        HandlerEvents(events_,n);  //成功，epoll_wait返回具体多少就绪数
                        break;
                }
            }
        }
        void HandlerEvents(struct epoll_event* events_,int num)
        {
            for(int i=0;i<num;i++)
            {
                int sock = events_[i].data.fd;
                uint32_t event = events_[i].events;
                if(events_[i].events&EPOLLIN)
                {
                    //读文件就绪
                    if(sock==listen_sock_)
                    {
                        //表示有新链接到来
                        struct sockaddr_in pre;
                        socklen_t len=sizeof(pre);
                        int fd=accept(listen_sock_,(sockaddr*)&pre,&len);
                        if(fd<0)
                            continue;
                        //把新的链接添加到epoll模型中
                        struct epoll_event acevent;
                        acevent.events=EPOLLIN;
                        acevent.data.fd=fd;
                        epoll_ctl(epfd_,EPOLL_CTL_ADD,fd,&acevent);
                    }
                    else{
                        //表示其他文件读数据就绪
                        char buffer[1024];
                        int s=read(sock,buffer,sizeof(buffer));
                        switch(s)
                        {
                            case 0:
                                //对端关闭
                                std::cout<<"client quit"<<std::endl;
                                close(sock);
                                //删除epoll模型中
                                epoll_ctl(epfd_,EPOLL_CTL_DEL,sock,nullptr);
                                break;
                            case -1:
                                //读取失败-- 暴力删除
                                std::cerr<<"read error"<<std::endl;
                                close(sock);
                                epoll_ctl(epfd_,EPOLL_CTL_DEL,sock,nullptr);
                                break;
                            default:
                                buffer[s]=0;   //没有解决数据的问题
                                std::cout<<"cliten syas: "<<buffer<<std::endl;
                                //添加写，一来一回
                                struct epoll_event ev;
                                ev.data.fd=sock;
                                ev.events=EPOLLIN|EPOLLOUT;
                                epoll_ctl(epfd_,EPOLL_CTL_MOD,sock,&ev);
                                break;
                        }
                    }
                }
                if(events_[i].events&EPOLLOUT)
                {
                    //写文件就绪
                    //无脑写入
                    std::string respond;
                    respond+="hello client,server syas!";
                    write(sock,respond.c_str(),respond.size());
                    //写入后删除读
                    struct epoll_event ev;
                    ev.data.fd=sock;
                    ev.events=EPOLLIN;
                    epoll_ctl(epfd_,EPOLL_CTL_MOD,sock,&ev);
                }  
            }
        }
        ~EpollServer()
        {
            if(listen_sock_>0)
                close(listen_sock_);
            if(epfd_>0)
                close(epfd_);
        }
    };
}